import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import org.ccnx.ccn.CCNHandle;
import org.ccnx.ccn.config.ConfigurationException;
import org.ccnx.ccn.impl.support.Log;
import org.ccnx.ccn.io.CCNFileInputStream;
import org.ccnx.ccn.io.CCNInputStream;
import org.ccnx.ccn.protocol.ContentName;
import org.ccnx.ccn.protocol.MalformedContentNameStringException;

public class Handler {
	String localDataRoot = "";
	String remoteURI = "ccnx:/";
	String relativePath = "/";
	
	
	DirInfo currentDirInfo;
	
	public Handler(String uri)
	{
		localDataRoot = Constants.defaultDataPath;
		remoteURI = PathResolver.formalizeURI(uri);
		currentDirInfo = new DirInfo();
		File infoFolder = new File(PathResolver.getLocalInfoPath(localDataRoot, ""));
		if(!infoFolder.exists())
			if(!infoFolder.mkdir())
				System.err.println("Create Info Folder Fail:" + PathResolver.getLocalInfoPath(localDataRoot, ""));
		
	}
	public Handler(String uri, String local)
	{
		this(uri);
		localDataRoot = local;
	}

	public void handle(String command)
	{
		if(command.startsWith("ls"))
		{
			System.out.println("ls ing:");
			if(command.length() < 3)
				ls(relativePath);
			else
				ls(command.substring(3));
		}
		else if(command.startsWith("refresh"))
		{
			System.out.println("refreshing:");
			lsRemote(relativePath);
			display(true);
		}
		else if(command.startsWith("cd") && command.length() > 3)
		{
			System.out.println("cd:" + command.substring(3));
			String dir = command.substring(3);
			changeDir(dir);
		}
		else if(command.startsWith("get") && command.length() > 4)
		{
			String filename = command.substring(4);
			
			String path = PathResolver.getFilePath(relativePath, filename);
			System.out.println("get file:" + filename + "\t" + path);
			getFilebyRPath(path);
		}
		else if(command.startsWith("q"))
		{
			System.out.println("Quiting...");
			//System.exit(0);
		}
		else
		{
			System.out.println("Illegal Command");
		}
	}
	private void ls(String relpath)
	{
		if (!relpath.endsWith("/"))
			relpath += "/";
		System.out.println("Handler::ls:" + relpath);
		if(!lsLocal(relpath))
		{
			if(!lsRemote(relpath))
			{
				System.err.println("Path do not exist");
				return;
			}
			display(true);
			return;
		}
		display(false);
	}

	private boolean lsLocal(String relpath)
	{
		System.out.println("Handler::lsLocal:" + PathResolver.getLocalInfoPath(localDataRoot, relpath));
		File file = new File(PathResolver.getLocalInfoPath(localDataRoot, relpath));
		if(!file.exists())
		{
			return false;
		}
		currentDirInfo.resolveLSFile(file);
		return true;
		
	}
	private boolean lsRemote(String relpath)
	{
		System.out.println("Handler::lsRemote:" + relpath);
		String localPath = PathResolver.getLocalInfoPath(localDataRoot, relpath);
		String uri = PathResolver.getInfoURI(remoteURI, relpath);
		
		if(!getFile(uri, localPath))
		{
			System.err.println("Cannot getFile:" + relpath + "lsRemote fail");
			return false;
		}
		
		lsLocal(relpath);
		return true;
		//currentDirInfo
	}
	protected void changeDir(String path)
	{
		System.out.println("Handler::changeDir:" + path);
		if(path.startsWith("/"))
		{
			System.out.println("changeDir:Absolute");
			if(!path.endsWith("/"))
				path += "/";
			relativePath = path;
			ls(path);
		}
		else if(path.equals("."))
		{
			System.out.println("changeDir:.");
			return;
		}
		else if(path.equals(".."))
		{	
			System.out.println("changeDir:..");
			relativePath =  PathResolver.getParentPath(relativePath);
			ls(relativePath);
		}
		else
		{
			System.out.println("changeDir:Relative");
			if(currentDirInfo.hasDir(path))
			{
				relativePath =  relativePath + path;
				ls(relativePath);
				return;
			}
			System.out.println("Path do not exist");
		}
	}
	
	private void getFilebyRPath(String relPath)
	{
		String fURI = PathResolver.getFileURI(remoteURI, relPath);
		String lPath = PathResolver.getLocalPath(localDataRoot, relPath);
		System.out.println("Handler::getRelativeFile:" + relPath + "\t" + fURI + "\t" + lPath);
		getFile(fURI, lPath);
	}
	protected boolean getFile(String uri, String localPath)
	{
		int readsize = 1024; 
		
		System.out.println("Handler::getFile:" + uri + "\t" + localPath);
		try {
			//prepare folder on path
			File localFile = new File(localPath);
			if (localFile.exists()) {
				if(!localFile.isFile())
				{
					System.err.println(localPath + "Not a File!");
					if(!localFile.delete())
					{
						System.err.println("Delete Folder Fail!");
					}
					if(!localFile.createNewFile())
					{
						System.err.println("Create File Fail!");
					}
				}
				else
				{
					System.out.println("Overwriting file: " + localPath);
				}
			}
			else
			{
				//if(!localFile.createNewFile())
				//{
				System.out.println("Creating folder on path.");
				if((localFile.mkdirs()))
				{
					System.out.println("Path created");
					localFile.delete();
				}
				else
					System.out.println("Path failed");
				if(!localFile.createNewFile())
					System.err.println("Create File Fail!!");
				}
			//}
			
			
			
			
			FileOutputStream output = new FileOutputStream(localFile);
			
			
			ContentName argName = ContentName.fromURI(uri);
			CCNHandle handle = CCNHandle.open();
			CCNInputStream ccnInput;
			ccnInput = new CCNFileInputStream(argName, handle);
			
			byte [] buffer = new byte[readsize];
			long starttime = System.currentTimeMillis();
			int readcount = 0;
			long readtotal = 0;
			while ((readcount = ccnInput.read(buffer)) != -1){
				readtotal += readcount;
				output.write(buffer, 0, readcount);
				output.flush();
			}
			System.out.println("ccngetfile took: "+(System.currentTimeMillis() - starttime)+"ms");
			System.out.println("Retrieved content " + localPath + " got " + readtotal + " bytes.");
			
		} catch (ConfigurationException e) {
			System.out.println("Configuration exception in ccngetfile: " + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (MalformedContentNameStringException e) {
			System.out.println("Malformed name: " + uri + " " + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			System.out.println("Cannot write file or read content. " + e.getMessage());
			e.printStackTrace();
			return false;
		}
		return true;
	}
	protected void display(boolean isNew)
	{
		if(isNew)
			System.out.println("isNew");
		currentDirInfo.display();
	}
}
